package org.example.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import org.example.Util.DataSourceUtil;
import org.example.DAO.UserDao;
import org.example.entity.User;
import org.example.impl.UserDaoImpl;
import org.example.Util.PasswordUtil;

@WebServlet("/userLogin")
public class UserloginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final int MAX_INACTIVE_INTERVAL = 30 * 60; // 30分钟
    private UserDao userDao;

    @Override
    public void init() throws ServletException {
        super.init();
        try {
            DataSource dataSource = DataSourceUtil.getDataSource();
            this.userDao = new UserDaoImpl(dataSource);
        } catch (Exception e) {
            throw new ServletException("初始化用户DAO失败", e);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        // 获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String rememberMe = request.getParameter("rememberMe");
        String redirect = request.getParameter("redirect"); // 获取重定向参数

        // 调试日志：打印接收到的重定向参数
        System.out.println("[DEBUG] 接收到的重定向参数: " + redirect);

        // 输入验证
        if (username == null || username.trim().isEmpty() ||
                password == null || password.trim().isEmpty()) {
            request.setAttribute("error", "用户名和密码不能为空");
            request.getRequestDispatcher("Userlogin.jsp").forward(request, response);
            return;
        }

        username = escapeHtml(username.trim());
        password = password.trim();

        try {
            System.out.println("[DEBUG] 登录尝试 - 用户名: " + username);

            // 查询用户
            User user = userDao.getUserByUsername(username);

            // 用户不存在
            if (user == null) {
                System.out.println("[DEBUG] 用户不存在: " + username);
                request.setAttribute("error", "用户名或密码错误");
                request.getRequestDispatcher("Userlogin.jsp").forward(request, response);
                return;
            }

            // 验证密码
            System.out.println("[DEBUG] 用户找到: " + user.getUsername());
            System.out.println("[DEBUG] 存储的哈希: " + user.getPassword());

            if (user.getPassword() == null || !user.getPassword().startsWith("$2a$")) {
                System.err.println("[ERROR] 密码哈希格式不正确，不是BCrypt格式");
                request.setAttribute("error", "系统错误: 密码格式不正确");
                request.getRequestDispatcher("Userlogin.jsp").forward(request, response);
                return;
            }

            boolean isMatch = PasswordUtil.verifyPassword(password, user.getPassword());
            System.out.println("[DEBUG] 密码验证结果: " + isMatch);

            if (!isMatch) {
                System.out.println("[DEBUG] === 详细验证过程 ===");
                System.out.println("[DEBUG] 输入密码: " + password);
                System.out.println("[DEBUG] 存储哈希: " + user.getPassword());
                String simulatedHash = PasswordUtil.encryptPassword(password);
                System.out.println("[DEBUG] 即时生成哈希: " + simulatedHash);
                System.out.println("[DEBUG] 即时验证结果: " + PasswordUtil.verifyPassword(password, simulatedHash));
                System.out.println("[DEBUG] 与存储哈希验证: " + PasswordUtil.verifyPassword(password, user.getPassword()));

                request.setAttribute("error", "用户名或密码错误");
                request.getRequestDispatcher("Userlogin.jsp").forward(request, response);
                return;
            }
            // 在doPost方法中添加以下代码：
            if (isMatch) {
                // 创建新会话前使旧会话无效
                HttpSession oldSession = request.getSession(false);
                if (oldSession != null) {
                    oldSession.invalidate();
                }

                // 创建新会话
                HttpSession session = request.getSession(true);
                session.setMaxInactiveInterval(30 * 60); // 30分钟

                // 设置会话属性
                session.setAttribute("user", user);
                session.setAttribute("userId", user.getId());

                // 添加JSESSIONID到URL以防止cookie被禁用
                String targetUrl = "Userindex.jsp"; // 默认目标
                if (redirect != null && !redirect.isEmpty() && isSafeRedirect(redirect, request)) {
                    targetUrl = redirect;
                }

                // 确保包含JSESSIONID
                String encodedUrl = response.encodeRedirectURL(targetUrl);
                System.out.println("DEBUG: 重定向至: " + encodedUrl);
                response.sendRedirect(encodedUrl);
                return;
            }

            // 登录成功，处理会话
            HttpSession session = request.getSession();
            session.invalidate(); // 防止会话固定攻击
            session = request.getSession(true);
            System.out.println("[DEBUG] 会话ID: " + session.getId()
                    + " | 是否新创建: " + session.isNew());
            session.setMaxInactiveInterval(MAX_INACTIVE_INTERVAL); // 30分钟超时

            // 设置会话属性（同时设置user和userId）
            session.setAttribute("user", user);
            System.out.println("[DEBUG] user.getId() 值: " + user.getId());
            session.setAttribute("userId", user.getId());
            System.out.println("[DEBUG] 会话ID: " + session.getId());
            System.out.println("[DEBUG] 会话userId: " + session.getAttribute("userId"));
            System.out.println("[DEBUG] 会话user: " + session.getAttribute("user"));

            System.out.println("[INFO] 用户登录成功: " + user.getUsername());

            // === 关键修改1：安全处理重定向参数 ===
            if (redirect != null && !redirect.isEmpty()) {
                // 安全校验：防止开放重定向漏洞
                if (isSafeRedirect(redirect,request)) {
                    // URL编码处理会话ID
                    String encodedUrl = response.encodeURL(redirect);
                    System.out.println("[DEBUG] 安全重定向到: " + encodedUrl);
                    response.sendRedirect(encodedUrl);
                    return;
                } else {
                    System.out.println("[WARN] 检测到不安全的重定向: " + redirect);
                }
            }

            // === 关键修改2：处理其他重定向场景 ===
            String referer = request.getHeader("Referer");
            if (referer != null && !referer.contains("Userlogin.jsp")) {
                // 安全校验来源页面
                if (isSafeRedirect(referer,request)) {
                    String encodedUrl = response.encodeURL(referer);
                    System.out.println("[DEBUG] 重定向到来源页面: " + encodedUrl);
                    response.sendRedirect(encodedUrl);
                    return;
                } else {
                    System.out.println("[WARN] 检测到不安全的来源页面: " + referer);
                }
            }

            // 默认重定向到用户主页
            String encodedUrl = response.encodeURL("Userindex.jsp");
            System.out.println("[DEBUG] 默认重定向到主页: " + encodedUrl);
            response.sendRedirect(encodedUrl);

        } catch (SQLException e) {
            System.err.println("[ERROR] 登录时数据库异常: " + e.getMessage());
            e.printStackTrace();
            request.setAttribute("error", "系统错误: 数据库访问异常，请稍后再试");
            request.getRequestDispatcher("Userlogin.jsp").forward(request, response);
        }
    }

    // 安全重定向校验方法（防止开放重定向漏洞）
    private boolean isSafeRedirect(String url, HttpServletRequest request) {
        return url != null &&
                (url.startsWith(request.getContextPath()) ||
                        url.startsWith("blog-list.jsp") ||
                        url.startsWith("Userindex.jsp") ||
                        url.startsWith("blog-detail.jsp") ||
                        url.startsWith("blog-edit.jsp"));
    }


    private String escapeHtml(String input) {
        if (input == null) return null;
        return input.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&#39;");
    }
}